/**
柯里化，英语：Currying(果然是满满的英译中的既视感)，
是把接受多个参数的函数变换成接受一个单一参数（最初函数的第一个参数）的函数
，并且返回接受余下的参数而且返回结果的新函数的技术。

柯里化就是一个参数收集器，当收集到的参数个数达到原函数(核心函数)的参数个数时，会执行原函数
*/

/** 1. 对单个函数订制实现柯里化*/
/*const add = (function (length) {
  let allArgs = []
  function _add(...args) {
    allArgs = [...allArgs, ...args]
    if (allArgs.length >= length) {
      const sum = allArgs.reduce((acc, curr) => acc + curr, 0)
      allArgs.length = 0
      return sum
    } else {
      return _add
    }
  }
  return _add
})(5)
console.log(add(1, 2, 3, 4, 5))//15
console.log(add(1)(2, 3)(4, 5))//15
console.log(add(1)(2)(3)(4)(5))//15*/

/** 2. 使用bind实现柯里化*/
/** 原理: fnX.bind(this1,a,b).bind(this2,c,d).bind(this3,e,f) === fnX.bind(this1,a,b,c,d,e,f)*/
/*function add(...args){
  return args.reduce((prev, cur) => prev + cur, 0)
}

console.log(add(1, 2, 3, 4, 5)) //15
console.log(add.bind(null, 1).bind(null, 2, 3).bind(null, 4, 5)()) //15
console.log(add.bind(null, 1).bind(null, 2).bind(null, 3).bind(null, 4).bind(null, 5)()) //15*/

/** 3. 通用版*/
/*function currying(fn, arr = []) {
  const len = fn.length // 获取当前函数的参数的个数,它和arguments不同,arguments是实际接收的,而它是期望接收的、可以接受的最大参数个数,是你定义函数时定义的形参个数
  console.log('len:',len)
  return function(...args) {
    // [1,2]
    arr = [...arr, ...args]
    if (arr.length < len) {
      return curring(fn, arr) // 递归 如果数量不够 不停的返回 函数，继续接受参数
    } else {
      return fn(...arr)
    }
  }
}*/
/** 简写版↓*/
function currying(fn, ...args){
  return args.length < fn.length ? (...innerArgs) => currying(fn, ...args, ...innerArgs) : fn(...args)
}

function add(a, b, c, d, e) {
  return a + b + c + d + e
}
//↑柯里化,偏函数↓ curring函数能将一个函数柯里化
const r = currying(add)(1, 2)(3)(4, 5, 6)
console.log(r) //15
